/******************************************************************************
 * Copyright (c) 2012 Sakai Project/Ho Chi Minh City University of Technology
 *****************************************************************************/

package edu.hcmut.managegroup.tool.jsf;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Set;

import javax.faces.application.FacesMessage;
import javax.faces.context.FacesContext;
import javax.faces.model.SelectItem;

import org.apache.commons.lang.StringUtils;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.sakaiproject.authz.api.Member;
import org.sakaiproject.authz.api.Role;
import org.sakaiproject.authz.api.SecurityService;
import org.sakaiproject.exception.IdUnusedException;
import org.sakaiproject.exception.PermissionException;
import org.sakaiproject.javax.PagingPosition;
import org.sakaiproject.site.api.Group;
import org.sakaiproject.site.api.Site;
import org.sakaiproject.site.api.SiteService;
import org.sakaiproject.site.api.SiteService.SelectionType;
import org.sakaiproject.site.api.SiteService.SortType;
import org.sakaiproject.user.api.UserDirectoryService;
import org.sakaiproject.user.api.UserNotDefinedException;

/**
 * This is a backing bean for the JSF manage-group app
 * 
 * @author nttin@cse.hcmut.edu.vn
 */
public class ManageGroupBean {

	private static Log log = LogFactory.getLog(ManageGroupBean.class);

	final private static String SITE_TYPE_PROJECT = "project";
	final private static String SITE_TYPE_COURSE = "course";
	
	public List<Site> sites;
	public List<String> siteId;
	public String listUserId;
	public String groupName;
	public String groupDescription;
	//to use this variable, must call loadTeacherWithSite
	public Map<String, List<String>> teacherAndHisSites;
	
	//Services
	private SiteService siteService;
	private SecurityService securityService;
	private UserDirectoryService userDirectoryService;

	public void setUserDirectoryService(UserDirectoryService userDirectoryService) {
		this.userDirectoryService = userDirectoryService;
	}

	public void setSiteService(SiteService siteService) {
		this.siteService = siteService;
	}
	
	public void setSecurityService(SecurityService securityService) {
		this.securityService = securityService;
	}

	public ManageGroupBean(){
		log.info("Manage Group bean -- constructor");
		sites = null;
		siteId = null;
		listUserId = "";
		groupName = "";
		groupDescription = "";
	}
	
	public SelectItem[] getAllSiteName(){
		int i = 0;
		sites = siteService.getSites(SelectionType.PUBVIEW, null, "", null, SortType.TITLE_ASC, new PagingPosition(1, 100));
		SelectItem[] ret = new SelectItem[sites.size()];
		for (Site site : sites) {
			ret[i++] = new SelectItem(site.getId(), site.getTitle());
		}
		return ret;
	}
	
	/**
	 * This method is used as an action for this tool. 
	 * When user click Add button, this method is called
	 */
	public void addStudentsToGroup(){
		Site site;
		if (securityService.isSuperUser(userDirectoryService.getCurrentUser().getId())) {
			try {
				// for each site id
				for(String sid : siteId){
					site = siteService.getSite(sid);
					//create new group
					Group newGroup = site.addGroup();
					newGroup.getProperties().addProperty("group_prop_wsetup_created", Boolean.TRUE.toString());
					newGroup.setProviderGroupId(null);
					newGroup.setTitle(groupName);
					newGroup.setDescription(groupDescription);
					
					//get input userId
					String userId[] = parseUserId(listUserId);
					for(String eid : userId){
						String id = userDirectoryService.getUserId(eid);
						//Check whether user had been in site or not
						if(!userInSite(id, site)){
							//add user to site
							//if site's type is "project", default add role for user is "access"
							if(SITE_TYPE_PROJECT.equals(site.getType())){
								site.addMember(id, "access", true, false);
							}
							//if site's type is "course", default add role for user is "student"
							else if(SITE_TYPE_COURSE.equals(site.getType())){
								site.addMember(id, "student", true, false);
							}
						} 
						//add user to new group.
						Role r = site.getUserRole(id);
						newGroup.addMember(id, r.getId(), true, false);
					}
					siteService.save(site);
				}
				resetParams();
			} catch (IdUnusedException e) {
				addMessage("The user'id " + e.getId() + " can be used for some actions");
				e.printStackTrace();
			} catch (PermissionException e) {
				addMessage("You don't have permission to do this.");
				e.printStackTrace();
			} catch (UserNotDefinedException e) {
				addMessage("Sorry, we can't find user with id: " + e.getId());
				e.printStackTrace();
			}
		}
	}

	/**
	 * @return Map with 2 value is teacher (user id) and list sites (site id) that he/she teach.
	 */
	public void loadTeacherWithSites(){
		Map<String, List<String>> ret = new HashMap<String, List<String>>();
		if (siteId == null){ 
			sites = siteService.getSites(SelectionType.PUBVIEW, null, "", null, SortType.TITLE_ASC, new PagingPosition(1, 100));
		}
		for(Site site : sites){
			Set<String> usrIds = site.getUsersHasRole("maintain");
			for(String id : usrIds){
				//because sometime admin will create site for teachers.
				//so we have to check and don't use it.
				if("admin".equals(id)) continue;
				//check whether we has user or not, 
				//if we already have this id, just add site to it.
				try {
					id = userDirectoryService.getUserEid(id);
					if(ret.containsKey(id)) {
						ret.get(id).add(site.getTitle());
					} 
					else {
						List<String> newSites = new ArrayList<String>();
						newSites.add(site.getTitle());
						ret.put(id, newSites);
					}
				} catch (UserNotDefinedException e) {
					e.printStackTrace();
				}
			}
		}
		teacherAndHisSites = ret;
	}
	
	public List<String> getTeacherId(){
		List<String> keys = new ArrayList<String>();
		if(teacherAndHisSites == null){
			//initialize teacherAndHisSites
			loadTeacherWithSites();
		}
		keys.addAll(teacherAndHisSites.keySet());
		return keys;
	}
	
	/**
	 * Check whether user had been in site or not.
	 * @param userId
	 * @param site
	 * @return
	 *  	true if userId had been in site, else return false
	 */
	public boolean userInSite(String userId, Site site){
		Member mem = site.getMember(userId);
		return mem == null ? false : true;
	}
	/**
	 * This method is used to reset all parameters.
	 */
	public void resetParams(){
		siteId = null;
		listUserId = "";
		groupName = "";
		groupDescription = "";
	}
	
	/**
	 * When user input list user id, we receive a string.
	 * We need part this string to list of string with each is a user id.
	 * @param inputString
	 * @return
	 */
	public String[] parseUserId(String inputString){
		//get each line from inputString that receive from user input.
		String line[] = inputString.split("\\r?\\n");
		//remove all control characters.
		for(String str : line){
			str = StringUtils.trimToNull(str);
		}
		return line;
	}
	
	
	/**
	 * This method is used to push message error to GUI.
	 * @param messageStr
	 * 		The message we want to push
	 */
	private void addMessage(String messageStr){
		FacesMessage message = new FacesMessage(messageStr);
		FacesContext.getCurrentInstance().addMessage(null, message);
	}
	
	//Getter & setter for all properties
	public List<Site> getSites() {
		return sites;
	}

	public void setSites(List<Site> sites) {
		this.sites = sites;
	}

	public String getListUserId() {
		return listUserId;
	}

	public void setListUserId(String listUserId) {
		this.listUserId = listUserId;
	}

	public String getGroupName() {
		return groupName;
	}

	public void setGroupName(String groupName) {
		this.groupName = groupName;
	}

	public String getGroupDescription() {
		return groupDescription;
	}

	public void setGroupDescription(String groupDescription) {
		this.groupDescription = groupDescription;
	}

	public List<String> getSiteId() {
		return siteId;
	}

	public void setSiteId(List<String> siteId) {
		this.siteId = siteId;
	}

	public Map<String, List<String>> getTeacherAndHisSites() {
		return teacherAndHisSites;
	}

}
